//===- StaticResolver.h----------------------------------------------------===//
// Part of the eld Project, under the BSD License
// See https://github.com/qualcomm/eld/LICENSE.txt for license information.
// SPDX-License-Identifier: BSD-3-Clause
//===----------------------------------------------------------------------===//
//
//                     The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#ifndef ELD_SYMBOLRESOLVER_STATICRESOLVER_H
#define ELD_SYMBOLRESOLVER_STATICRESOLVER_H
#include "eld/SymbolResolver/ResolveInfo.h"
#include "eld/SymbolResolver/Resolver.h"
#include "llvm/ADT/StringRef.h"
#include <string>

namespace eld {

class NamePool;
class LinkerConfig;

/** \class StaticResolver
 */
class StaticResolver : public Resolver {
public:
  enum LinkAction {
    FAIL,   /* abort.  */
    NOACT,  /* no action.  */
    UND,    /* override by symbol undefined symbol.  */
    WEAK,   /* override by symbol weak undefined.  */
    DEF,    /* override by symbol defined.  */
    DEFW,   /* override by symbol weak defined.  */
    DEFD,   /* override by symbol dynamic defined.  */
    DEFWD,  /* override by symbol dynamic weak defined.  */
    MDEFD,  /* mark symbol dynamic defined.  */
    MDEFWD, /* mark symbol dynamic weak defined.  */
    DUND,   /* override dynamic defined symbol by undefined one.  */
    DUNDW,  /* oevrride dynamic defined symbol by weak undefined one.  */
    COM,    /* override by symbol common.  */
    CREF,   /* Possibly warn about common reference to defined symbol.  */
    CDEF,   /* redefine existing common symbol.  */
    BIG,    /* override by symbol common using largest size.  */
    MBIG,   /* mark common symbol by larger size.  */
    MDEF,   /* multiple definition error.  */
  };

private:
  // These are the values generated by the bit codes.
  /** Encoding:
   *  D -> define
   *  U -> undefine
   *  d -> dynamic
   *  w -> weak
   *  C -> common
   */
  enum {
    U = ResolveInfo::GlobalFlag | ResolveInfo::RegularFlag |
        ResolveInfo::UndefineFlag,
    w_U = ResolveInfo::WeakFlag | ResolveInfo::RegularFlag |
          ResolveInfo::UndefineFlag,
    d_U = ResolveInfo::GlobalFlag | ResolveInfo::DynamicFlag |
          ResolveInfo::UndefineFlag,
    wd_U = ResolveInfo::WeakFlag | ResolveInfo::DynamicFlag |
           ResolveInfo::UndefineFlag,
    D = ResolveInfo::GlobalFlag | ResolveInfo::RegularFlag |
        ResolveInfo::DefineFlag,
    w_D = ResolveInfo::WeakFlag | ResolveInfo::RegularFlag |
          ResolveInfo::DefineFlag,
    d_D = ResolveInfo::GlobalFlag | ResolveInfo::DynamicFlag |
          ResolveInfo::DefineFlag,
    wd_D = ResolveInfo::WeakFlag | ResolveInfo::DynamicFlag |
           ResolveInfo::DefineFlag,
    C = ResolveInfo::GlobalFlag | ResolveInfo::RegularFlag |
        ResolveInfo::CommonFlag,
    w_C = ResolveInfo::WeakFlag | ResolveInfo::RegularFlag |
          ResolveInfo::CommonFlag,
    d_C = ResolveInfo::GlobalFlag | ResolveInfo::DynamicFlag |
          ResolveInfo::CommonFlag,
    wd_C = ResolveInfo::WeakFlag | ResolveInfo::DynamicFlag |
           ResolveInfo::CommonFlag,
  };

  enum ORDINATE {
    U_ORD,
    w_U_ORD,
    d_U_ORD,
    wd_U_ORD,
    D_ORD,
    w_D_ORD,
    d_D_ORD,
    wd_D_ORD,
    C_ORD,
    w_C_ORD,
    Cs_ORD,
    LAST_ORD
  };

public:
  virtual ~StaticResolver();

  /// shouldOverride - Can resolver override the symbol pOld by the symbol pNew?
  /// @return successfully resolved, return true; otherwise, return false.
  /// @param pOld the symbol which may be overridden.
  /// @param pNew the symbol which is used to replace pOld
  virtual bool resolve(ResolveInfo &OldSymbol, const ResolveInfo &NewSymbol,
                       bool &CurOverride, LDSymbol::ValueType Value,
                       LinkerConfig *Config,
                       bool IsPostLtoPhase) const override;

  unsigned int getOrdinate(const ResolveInfo &CurInfo) const {
    if (CurInfo.isAbsolute() && CurInfo.isDyn())
      return d_D_ORD;
    if (CurInfo.isAbsolute())
      return D_ORD;
    if (CurInfo.isCommon() && CurInfo.isDyn())
      return Cs_ORD;
    if (CurInfo.isCommon() && CurInfo.isDefine())
      return C_ORD;
    if (CurInfo.isCommon() && CurInfo.isWeak())
      return w_C_ORD;
    return CurInfo.info();
  }

  llvm::StringRef getOrdinateDesc(unsigned int POrdinate) const {
    switch (POrdinate) {
    case U_ORD:
      return "undefined";
    case w_U_ORD:
      return "weak unefined";
    case d_U_ORD:
      return "dynamic undefined";
    case wd_U_ORD:
      return "dynamic weak undefined";
    case D_ORD:
      return "defined";
    case w_D_ORD:
      return "weak defined";
    case d_D_ORD:
      return "dynamic defined";
    case wd_D_ORD:
      return "dynamic weak defined";
    case C_ORD:
      return "common";
    case w_C_ORD:
      return "common (weak)";
    case Cs_ORD:
      return "common";
    case LAST_ORD:
    default:
      return "Unknown";
    }
  }
};

} // namespace eld

#endif
